package cn.kduck.plugin.idea.generate.impl;

import cn.kduck.plugin.idea.generate.CodeGenerator;
import cn.kduck.plugin.idea.utils.GeneratorUtils;
import cn.kduck.plugin.idea.utils.StringUtils;
import com.intellij.openapi.project.Project;
import com.intellij.psi.*;
import com.intellij.psi.javadoc.PsiDocComment;
import com.intellij.psi.search.GlobalSearchScope;

public class EnumBasedGenerator implements CodeGenerator {
    @Override
    public String code() {
        return "ENUM";
    }

    @Override
    public void updateCode(Project project, PsiClass javaClass, PsiField[] selectFields) {
        PsiElementFactory elementFactory = JavaPsiFacade.getElementFactory(project);

        PsiClass parentClass = GeneratorUtils.getValueMapClass(project);
        boolean isValueMap = GeneratorUtils.isValueMap(parentClass);

        //！！！！！涉及到类的构造构成，不要随便更换顺序！！！！！
        GeneratorUtils.createConstructor(elementFactory,project, javaClass);
        GeneratorUtils.addExtendClass(elementFactory,javaClass,parentClass);

        //先判断枚举类是否已经存在，仅是想对属性进行增加
        PsiClassType stringType = PsiClassType.getTypeByName(String.class.getName(), project, GlobalSearchScope.allScope(project));

        boolean isExist = true;
        PsiClass fieldEnumClass = javaClass.findInnerClassByName(javaClass.getName() + "FieldEnum", false);
        if(fieldEnumClass == null){
            fieldEnumClass = elementFactory.createEnum(javaClass.getName()+"FieldEnum");

            PsiField fieldName = elementFactory.createField("fieldName", stringType);
            fieldName.getModifierList().setModifierProperty(PsiModifier.FINAL, true);
            PsiField attrName = elementFactory.createField("attrName", stringType);
            attrName.getModifierList().setModifierProperty(PsiModifier.FINAL, true);
            fieldEnumClass.add(fieldName);
            fieldEnumClass.add(attrName);

            PsiMethod constructorMethod = elementFactory.createConstructor();
            PsiParameter fieldNameParam = elementFactory.createParameter("fieldName", stringType);
            PsiParameter attrNameParam = elementFactory.createParameter("attrName", stringType);
            PsiParameterList parameterList = constructorMethod.getParameterList();
            parameterList.add(fieldNameParam);
            parameterList.add(attrNameParam);

            String bodyText = "{this.fieldName=fieldName;this.attrName=attrName;}";
            PsiCodeBlock codeBlock = elementFactory.createCodeBlockFromText(bodyText, null);
            constructorMethod.getBody().replace(codeBlock);
            fieldEnumClass.add(constructorMethod);
            isExist = false;
        }

        PsiJavaFile javaFile = (PsiJavaFile) javaClass.getContainingFile();

        for (PsiField field : selectFields) {

            String comment = GeneratorUtils.getCommentForField(field);

            String enumConstantFieldName = StringUtils.upperCaseWithSeparator(field.getName(), "_");
            String enumConstantField = enumConstantFieldName +"(\"" + enumConstantFieldName + "\",\"" + field.getName() + "\")";
            PsiEnumConstant enumConstant = elementFactory.createEnumConstantFromText(enumConstantField, fieldEnumClass);

            if(comment != null){
                PsiDocComment fieldComment = elementFactory.createDocCommentFromText("/** " + comment + " */");
                enumConstant.addBefore(fieldComment, enumConstant.getFirstChild());
            }

            fieldEnumClass.add(enumConstant);

            PsiMethod setterMethod = GeneratorUtils.createSetterMethod(elementFactory, field, isValueMap,fn->StringUtils.upperCaseWithSeparator(fn, "_") + ".getAttrName()");
            PsiMethod getterMethod = GeneratorUtils.createGetterMethod(elementFactory, field, isValueMap,fn->StringUtils.upperCaseWithSeparator(fn, "_") + ".getAttrName()");
            javaClass.add(setterMethod);
            javaClass.add(getterMethod);

            field.delete();
        }

        if(!isExist){
            PsiMethod fieldNameGetterMethod = createStandardGetterMethod(elementFactory, stringType,"fieldName");
            PsiMethod attrNameGetterMethod = createStandardGetterMethod(elementFactory, stringType,"attrName");
            fieldEnumClass.add(fieldNameGetterMethod);
            fieldEnumClass.add(attrNameGetterMethod);

            javaClass.add(fieldEnumClass);

            PsiClass innerClassByName = javaClass.findInnerClassByName(fieldEnumClass.getName(), false);
            PsiImportList importList = javaFile.getImportList();
            PsiImportStaticStatement enumImportStatement = elementFactory.createImportStaticStatement(innerClassByName, "*");
            importList.add(enumImportStatement);
        }

//        javaFile.getContainingFile().getVirtualFile().refresh();
    }

    private static PsiMethod createStandardGetterMethod(PsiElementFactory elementFactory, PsiClassType stringType, String name) {
        PsiMethod method = elementFactory.createMethod("get" + StringUtils.upperFirstChar(name), stringType);
        String fieldNameBodyText = "{return " + name + ";}";
        PsiCodeBlock fieldNameCodeBlock = elementFactory.createCodeBlockFromText(fieldNameBodyText, null);

        method.getBody().replace(fieldNameCodeBlock);
        return method;
    }


    @Override
    public void newCode(Project project, PsiClass javaClass, PsiField[] selectFields) {

    }
}
